﻿// ***********************************************************************
// Assembly         : Delta_entidad
// Author           : Juan Alberto Cerino Gomez
// Created          : 02-18-2013
//
// Last Modified By : Juan Alberto Cerino Gomez
// Last Modified On : 06-02-2013
// ***********************************************************************
// <copyright file="ControlDinamico.cs" company="Delta Bussines">
//     Copyright (c) 2013  Delta Bussines. All rights reserved.
// </copyright>
// <summary></summary>
// ***********************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Dynamic;
using System.Linq.Expressions;

namespace Delta_entidad.Base
{
    /// <summary>
    /// Clase que se encarga de controlar los datos dinamicos de la entidad.
    /// </summary>
    public class ControlDinamico : DynamicMetaObject
    {
        /// <summary>
        ///Constructor de la clase.
        /// </summary>
        /// <param name="expression">La expresión a usar para el enlace.</param>
        /// <param name="value">El valor a enlazar.</param>
        public ControlDinamico(Expression expression, TipoBase value)
            : base(expression, BindingRestrictions.Empty, value) { }

        /// <summary>
        /// Realiza el enlace de la operación de obtención de miembros dinámica.
        /// </summary>
        /// <param name="binder">Una instancia de la clase <see cref="T:System.Dynamic.GetMemberBinder" /> que representa los detalles de la operación dinámica.</param>
        /// <returns>Nuevo objeto <see cref="T:System.Dynamic.DynamicMetaObject" /> que representa el resultado del enlace.</returns>
        public override DynamicMetaObject BindGetMember
                (GetMemberBinder binder)
        {
            var self = this.Expression;
            var bag = (TipoBase)base.Value;



            Expression target;

            var keyExpr = Expression.Constant(binder.Name);
            var valueExpr = Expression.Variable(typeof(object));

            var dictCheckExpr =
                Expression.Call(
                    Expression.Convert(self, typeof(TipoBase)),
                    typeof(TipoBase).GetMethod("TryGetValue"),
                    keyExpr,
                    valueExpr
                );
            var dictFailExpr =
                Expression.Block(
                    binder.FallbackGetMember(this).Expression,
                    Expression.Default(typeof(object))
                );

            target =
                Expression.Block(
                    new[] { valueExpr },
                    Expression.Condition(
                        dictCheckExpr,
                        valueExpr,
                        dictFailExpr
                    )
                );
            
            var restrictions = BindingRestrictions
                                   .GetInstanceRestriction(self, bag);

            return new DynamicMetaObject(target, restrictions);
        }


        /// <summary>
        /// Realiza el enlace de la operación de establecimiento de miembros dinámica.
        /// </summary>
        /// <param name="binder">Una instancia de la clase <see cref="T:System.Dynamic.SetMemberBinder" /> que representa los detalles de la operación dinámica.</param>
        /// <param name="value"><see cref="T:System.Dynamic.DynamicMetaObject" /> que representa el valor para la operación de establecimiento de miembros.</param>
        /// <returns>Nuevo objeto <see cref="T:System.Dynamic.DynamicMetaObject" /> que representa el resultado del enlace.</returns>
        public override DynamicMetaObject BindSetMember(
            SetMemberBinder binder, DynamicMetaObject value)
        {
            var self = this.Expression;

            var keyExpr = Expression.Constant(binder.Name);
            var valueExpr = Expression.Convert(
                                value.Expression,
                                typeof(object)
                            );

            var target = Expression.Block(
                Expression.Call(
                    Expression.Convert(self, typeof(TipoBase)),
                    typeof(TipoBase).GetMethod("SetValue"),
                    keyExpr,
                    valueExpr
                ),
                valueExpr);

            var restrictions = BindingRestrictions
                                  .GetTypeRestriction(self, typeof(TipoBase));

            return new DynamicMetaObject(target, restrictions);
        }

        /// <summary>
        /// Devuelve la enumeración de todos los nombres de miembro dinámicos.
        /// </summary>
        /// <returns>Lista de nombres de miembro dinámicos.</returns>
        public override IEnumerable<string> GetDynamicMemberNames()
        {
            var bag = (TipoBase)base.Value;

            return bag.GetKeys();
        }
    }
}
